package
{
	import com.wanhu.player.*;

	import flash.display.MovieClip;
	import flash.events.*;
	import flash.external.*;
	import flash.media.*;
	import flash.net.*;
	import flash.utils.*;

	[SWF(width="640", height="480", backgroundColor="#ffffff", frameRate="24")]
	public class customerPlayer extends MovieClip
	{
		private var nc:NetConnection;

		// after connection to stratus, publish listener stream to wait for incoming call 
		private var listenerStream:NetStream;

		private var pingTimer:Timer=new Timer(Math.random() * 60000 + 60000);
		private var lookupTimer:Timer=new Timer(Math.random() * 10000 + 10000);
		private var partnerDisconnectTimer:Timer=new Timer(2000, 1);

		// caller's incoming stream that is connected to callee's listener stream
		private var controlStream:NetStream;

		// outgoing media stream (audio, video, text and some control messages)
		//private var Supervisor.outgoingStream:NetStream;

		// incoming media stream (audio, video, text and some control messages)
		private var incomingStream:NetStream;

		private var broadcastNc:NetConnection;

		private var rtmpNow:String="rtmfp://p2p.rtmfp.net/96a22fb3ac1530b95f46b3eb-6fe46a9e6c9f/";
		private var rtmpMulticast:String="rtmfp://localhost/"; //rtmfp://p2p.rtmfp.net/96a22fb3ac1530b95f46b3eb-6fe46a9e6c9f/";

		//private var Supervisor.sendStream:NetStream;
		private var receiveStream:NetStream;

		private const CCNotConnected:int=0;
		private const CCConnecting:int=1;
		private const CCConnected:int=2
		private const CCRegistered:int=3;
		private const CCDisconnecting:int=4;

		private const CCCallNotReady:int=0;
		private const CCCallReady:int=1;
		private const CCCallCalling:int=2;
		private const CCCallRinging:int=3;
		private const CCCallEstablished:int=4;
		private const CCCallFailed:int=5;

		private var gracefulDisconnect:Boolean;

		public function customerPlayer()
		{
			super();
			init();
			this.addChild(Supervisor.player);

		}

		private function init():void
		{
			Supervisor.conStatus=CCNotConnected;
			gracefulDisconnect=false;
			Supervisor.js.callBack("defaultValues", function():Object
			{
				setTimeout(function():void
				{
					try
					{
						Supervisor.player.initVideo();
					}
					catch (e:*)
					{
					}
				}, 100);
				return Constants.DEFAULT_VARS;
			});

			Supervisor.js.callBack("disconnect", function():void
			{
				try
				{
					removeConnection();
					partnerDisconnected(null);
				}
				catch (e:*)
				{

				}
			});

			Supervisor.js.callBack("sendOrder", function(message:*):void
			{
				try
				{
					if (Supervisor.callStatus == CCCallEstablished)
					{
						if (Supervisor.outgoingStream)
						{
							Supervisor.outgoingStream.send("sendOrder", message);
						}
					}
				}
				catch (e:*)
				{

				}
			});

			Supervisor.js.callBack("getCams", function():Array
			{
				return Camera.names;
			});

			Supervisor.js.callBack("getMics", function():Array
			{
				return Microphone.names;
			});

			Supervisor.js.callBack("initVideo", function():void
			{
				try
				{
					Supervisor.player.initVideo();
				}
				catch (e:*)
				{

				}
			});

			Supervisor.js.callBack("stop", function():void
			{
				partnerDisconnected(null);
			});

			Supervisor.js.callBack("start", function():void
			{
			});

			Supervisor.js.callBack("broadcast", function():void
			{
				try
				{
					if (Supervisor.conStatus == CCConnected && Supervisor.userType == 1 && Supervisor.boradcastStatus == 0)
					{
						setupStream();
						Supervisor.boradcastStatus=1;
					}
				}
				catch (e:*)
				{

				}
			});

			Supervisor.js.callBack("getBroadcastStatus", function():Boolean
			{
				return (Supervisor.boradcastStatus == 1);
			});

			Supervisor.js.callBack("unBroadcast", function():void
			{
				try
				{
					if (Supervisor.boradcastStatus == 1)
					{
						if (Supervisor.sendStream)
						{
							try
							{
								Supervisor.sendStream.close();
							}
							catch (e:*)
							{
							}
							Supervisor.sendStream.removeEventListener(NetStatusEvent.NET_STATUS, broadcastStream);
							Supervisor.sendStream=null;
						}
						Supervisor.boradcastStatus=0;
					}
				}
				catch (e:*)
				{

				}
			});

			Supervisor.js.callBack("setRegion", function(rr:int):void
			{
				Supervisor.region_id=String(rr);
				setTimeout(connectInstance, 30);
			});
		}

		private function connectInstance():void
		{
			Supervisor.conStatus=CCConnecting;
			Supervisor.callStatus=CCCallNotReady;
			nc=new NetConnection;
			nc.connect(rtmpNow);
			nc.addEventListener(NetStatusEvent.NET_STATUS, getStream);

			if (this.loaderInfo.parameters["userType"])
			{
				Supervisor.userType=int(this.loaderInfo.parameters["userType"]);
			}

			pingTimer.addEventListener(TimerEvent.TIMER, onPingTimer);
			lookupTimer.addEventListener(TimerEvent.TIMER, onLookupTimer);
			partnerDisconnectTimer.addEventListener(TimerEvent.TIMER, partnerDisconnected);
			broadcastNc=new NetConnection;
			broadcastNc.addEventListener(NetStatusEvent.NET_STATUS, broadcastStream);
		}

		private function broadcastStream(event:NetStatusEvent):void
		{
			Debug.print(event.info.code);

			switch (event.info.code)
			{
				case "NetConnection.Connect.Success":
					break;
				case "NetStream.Connect.Success":
					if (receiveStream)
					{
						receiveStream.play("multicast");
						Supervisor.player.attach(receiveStream);
					}
					break;
			}
		}

		private function setupStream():void
		{
			var groupspec:GroupSpecifier=new GroupSpecifier(nc.nearID);
			groupspec.serverChannelEnabled=true;
			groupspec.multicastEnabled=true;

			Supervisor.sendStream=new NetStream(nc, groupspec.groupspecWithAuthorizations());
			Supervisor.sendStream.addEventListener(NetStatusEvent.NET_STATUS, broadcastStream);

			if (Supervisor.cam)
			{
				if (Supervisor.sendVideo)
				{
					Supervisor.sendStream.attachCamera(Supervisor.cam);
				}
				else
				{
					Supervisor.sendStream.attachCamera(null);
				}
			}
			if (Supervisor.mic)
			{
				Supervisor.sendStream.attachAudio(Supervisor.mic);
			}
			Supervisor.sendStream.publish("multicast");
		}

		private function setupReceiveStream():void
		{
			Debug.print("setupReceiveStream " + Supervisor.broadcast);
			if (Supervisor.broadcast != null && Supervisor.broadcast != "")
			{
				var groupspec:GroupSpecifier=new GroupSpecifier(Supervisor.broadcast);
				groupspec.serverChannelEnabled=true;
				groupspec.multicastEnabled=true;

				receiveStream=new NetStream(nc, groupspec.groupspecWithAuthorizations());
				receiveStream.addEventListener(NetStatusEvent.NET_STATUS, broadcastStream);
			}
			Debug.print("setupReceiveStream " + Supervisor.broadcast);
		}

		private function getStream(e:NetStatusEvent):void
		{
			Debug.print("getStream:" + e.info.code);
			switch (e.info.code)
			{
				case "NetConnection.Connect.Success":
					onPingTimer(null);
					pingTimer.start();
					listenStream();
					Supervisor.conStatus=CCConnected;
					var sendBroadcast:Boolean=String(Supervisor.js.getVar(Constants.SEND_BROADCAST)) == "true";
					if (sendBroadcast && Supervisor.userType == 1 && Supervisor.boradcastStatus == 0)
					{
						setupStream();
						Supervisor.boradcastStatus=1;
					}
					break;
				case "NetStream.Connect.Success":
					if (receiveStream)
					{
						receiveStream.play("multicast");
						Supervisor.player.attach(receiveStream);
					}
					break;
				case "NetStream.Connect.Closed":
					this.partnerDisconnectTimer.reset();
					this.partnerDisconnectTimer.stop();
					this.partnerDisconnectTimer.start();
					break;
				case "NetConnection.Connect.Closed":
					pingTimer.stop();
					pingTimer.reset();
					removeConnection();
					Supervisor.conStatus=CCConnecting;
					setTimeout(function():void
					{
						nc.connect(rtmpNow);
					}, 50);
					break;
				case "NetConnection.Connect.Rejected":
				case "NetConnection.Connect.Failed":
					pingTimer.stop();
					pingTimer.reset();
					removeConnection();
					Supervisor.conStatus=CCConnecting;
					setTimeout(function():void
					{
						nc.connect(rtmpNow);
					}, 50);
					break;
				default:
					break;
			}
		}

		private function partnerDisconnected(event:TimerEvent):void
		{
			disconnect();

			Debug.print("partner disconnect..");
			Supervisor.player.attach();
			try
			{
				Supervisor.outgoingStream.send("gracefullyDisconnect", Supervisor.otherId);
			}
			catch (e:Error)
			{
			}
			Debug.print("partner disconnect..");
			Supervisor.otherId=null;
			Supervisor.callStatus=CCCallReady;

			Debug.print("partner disconnect..");
			if (incomingStream)
			{
				incomingStream.close();
				incomingStream.removeEventListener(NetStatusEvent.NET_STATUS, incomingStreamHandler);
				incomingStream=null;
			}

			Debug.print("partner disconnect..");
			if (Supervisor.outgoingStream)
			{
				Supervisor.outgoingStream.attachCamera(null);
				Supervisor.outgoingStream.attachAudio(null);
				Supervisor.outgoingStream.close();
				Supervisor.outgoingStream.removeEventListener(NetStatusEvent.NET_STATUS, outgoingStreamHandler);
				Supervisor.outgoingStream=null;
			}

			Debug.print("partner disconnect..");
			if (controlStream)
			{
				controlStream.close();
				controlStream.removeEventListener(NetStatusEvent.NET_STATUS, controlHandler);
				controlStream=null;
			}
			Debug.print("partner disconnect..");
		}

		private function listenStream():void
		{
			listenerStream=new NetStream(nc, NetStream.DIRECT_CONNECTIONS);
			listenerStream.addEventListener(NetStatusEvent.NET_STATUS, listenerHandler);
			listenerStream.publish("RVC");
			var c:Object=new Object();
			c.onPeerConnect=onPeerConnect;
			listenerStream.client=c;
		}

		private function onPeerConnect(caller:Object):Boolean
		{
			Debug.print("connecting...." + caller.farID);
			if (caller != null && caller.farID != null)
			{
				setCallEstablished();
				incomingStream=new NetStream(nc, caller.farID);
				incomingStream.addEventListener(NetStatusEvent.NET_STATUS, incomingStreamHandler);
				incomingStream.play("media-requester");
				Supervisor.otherId=incomingStream.farID;

				//Debug.print("speaker volume:" + _gv.getValue(GlobalVars.SPEAKER_VOLUME));

				var st:SoundTransform=new SoundTransform(1);
				incomingStream.soundTransform=st;

				Supervisor.player.attach(incomingStream);

				gracefulDisconnect=false;
				var i:Object=new Object();
				i.gracefullyDisconnect=function(id:String):void
				{
					gracefulDisconnect=true;
				};
				i.sendOrder=function(order:String):void
				{
					Debug.print("partner: " + order);
					Supervisor.js.call("cr_addCart", order);
				};
				incomingStream.client=i;

				if (Supervisor.outgoingStream)
				{
					Supervisor.outgoingStream.removeEventListener(NetStatusEvent.NET_STATUS, outgoingStreamHandler);
					try
					{
						Supervisor.outgoingStream.close();
					}
					catch (e:Error)
					{
					}
				}
				// Publishing my own media
				Supervisor.outgoingStream=new NetStream(nc, NetStream.DIRECT_CONNECTIONS);
				Supervisor.outgoingStream.addEventListener(NetStatusEvent.NET_STATUS, outgoingStreamHandler);
				Supervisor.outgoingStream.publish("media-responder");
				if (Supervisor.cam)
				{
					if (Supervisor.sendVideo)
					{
						Supervisor.outgoingStream.attachCamera(Supervisor.cam);
					}
					else
					{
						Supervisor.outgoingStream.attachCamera(null);
					}
				}

				if (Supervisor.mic)
				{
					Supervisor.outgoingStream.attachAudio(Supervisor.mic);
				}
				return true;
			}
			return false;
		}

		private function onSendPeerConnect(caller:Object):Boolean
		{
			Debug.print("connecting...." + caller.farID);
			if (caller != null && caller.farID != null)
			{
				setCallEstablished();
				incomingStream=new NetStream(nc, caller.farID);
				incomingStream.addEventListener(NetStatusEvent.NET_STATUS, incomingStreamHandler);
				incomingStream.play("media-responder");
				Supervisor.otherId=incomingStream.farID;

				//Debug.print("speaker volume:" + _gv.getValue(GlobalVars.SPEAKER_VOLUME));

				var st:SoundTransform=new SoundTransform(1);
				incomingStream.soundTransform=st;

				Supervisor.player.attach(incomingStream);

				gracefulDisconnect=false;
				var i:Object=new Object();
				i.gracefullyDisconnect=function(id:String):void
				{
					gracefulDisconnect=true;
				};
				i.sendOrder=function(order:String):void
				{
					Debug.print("partner: " + order);
					Supervisor.js.call("cr_addCart", order);
				};
				incomingStream.client=i;
				return true;
			}
			return false;
		}

		private function setCallEstablished():void
		{
			Supervisor.callStatus=CCCallEstablished;
		}

		private function listenerHandler(event:NetStatusEvent):void
		{
			Debug.print("listenerHandler:" + event.info.code);
			switch (event.info.code)
			{
			}
		}

		private function disconnect():void
		{
			Reception.post(Reception.CUT, function(loadObject:*, pObject:Object):void
			{
			});
			//Detach
		}

		private function removeConnection():void
		{
			Reception.post(Reception.REMOVE, function(loadObject:*, pObject:Object):void
			{
			});
		}

		private function onPingTimer(event:TimerEvent):void
		{
			Supervisor.nearID=nc.nearID;
			Reception.post(Reception.PING, pingRoute);
		}

		private function pingRoute(loadObject:*, pObject:Object):void
		{
			Debug.print("pingRoute:" + loadObject);
			if (Supervisor.userType == 0 && (Supervisor.otherId == null || Supervisor.otherId == ""))
			{
				onLookupTimer(null);
				lookupTimer.start();
			}
		}

		private function onLookupTimer(event:TimerEvent):void
		{
			Supervisor.nearID=nc.nearID;
			Reception.post(Reception.LOOKUP, lookupRoute);
		}

		private function lookupRoute(loadObject:*, pObject:Object):void
		{
			Debug.print("lookupRoute:" + loadObject);
			if (loadObject != null)
			{
				if (loadObject.farID != null && loadObject.farID != "")
				{
					Debug.print("farID" + loadObject.farID);
					Supervisor.otherId=loadObject.farID;
					lookupTimer.stop();
					lookupTimer.reset();
					Supervisor.callStatus=CCCallCalling;
					connectToOther();
				}
				else if (loadObject.broadcast != null && loadObject.broadcast != "" && Supervisor.broadcast != loadObject.broadcast)
				{
					Debug.print("broadcast" + loadObject.broadcast);
					Supervisor.broadcast=loadObject.broadcast;
					if (Supervisor.userType == 0)
					{
						setupReceiveStream();
					}
				}
				var waitingCount:int=0;
				if (loadObject.waitingCount)
				{
					try
					{
						waitingCount=int(loadObject.waitingCount);
					}
					catch (e:*)
					{
					}
				}
				Supervisor.js.call("cr_warn", waitingCount);
			}
		}

		private function connectToOther():void
		{
			Supervisor.callStatus=CCCallReady;

			if (controlStream)
			{
				controlStream.removeEventListener(NetStatusEvent.NET_STATUS, controlHandler);
				try
				{
					controlStream.close();
					controlStream=null;
				}
				catch (e:Error)
				{
				}
			}
			controlStream=new NetStream(nc, Supervisor.otherId);
			controlStream.addEventListener(NetStatusEvent.NET_STATUS, controlHandler);
			controlStream.play("RVC");

			// caller publishes media stream
			if (Supervisor.outgoingStream)
			{
				Supervisor.outgoingStream.removeEventListener(NetStatusEvent.NET_STATUS, outgoingStreamHandler);
				try
				{
					Supervisor.outgoingStream.close();
				}
				catch (e:Error)
				{
				}
			}
			Supervisor.outgoingStream=new NetStream(nc, NetStream.DIRECT_CONNECTIONS);
			Supervisor.outgoingStream.addEventListener(NetStatusEvent.NET_STATUS, outgoingStreamHandler);
			Supervisor.outgoingStream.publish("media-requester");

			if (incomingStream)
			{
				incomingStream.removeEventListener(NetStatusEvent.NET_STATUS, incomingStreamHandler);
				try
				{
					incomingStream.close();
				}
				catch (e:Error)
				{
				}
			}
			var o:Object=new Object;

			o.onPeerConnect=onSendPeerConnect;
			Supervisor.outgoingStream.client=o;
			if (Supervisor.cam)
			{
				if (Supervisor.sendVideo)
				{
					Supervisor.outgoingStream.attachCamera(Supervisor.cam);
				}
				else
				{
					Supervisor.outgoingStream.attachCamera(null);
				}
			}

			if (Supervisor.mic)
			{
				Supervisor.outgoingStream.attachAudio(Supervisor.mic);
			}
		}

		private function controlHandler(event:NetStatusEvent):void
		{
			trace("controlHandler ==> " + event.info.code);
			switch (event.info.code)
			{
				case "NetStream.Play.Failed":
					break;
				case "NetStream.Play.Start":

					break;
			}
		}

		private function incomingStreamHandler(event:NetStatusEvent):void
		{
			Debug.print("incomingStreamHandler ==> " + event.info.code);
			switch (event.info.code)
			{
				case "NetStream.Play.UnpublishNotify":
					break;
				case "NetStream.Play.Start":
					break;
			}
		}

		private function outgoingStreamHandler(event:NetStatusEvent):void
		{
			Debug.print("outgoingStreamHandler ==> " + event.info.code);
			switch (event.info.code)
			{
				case "NetStream.Play.Start":
					break;
				case "NetStream.Publish.Start":
					break;
				case "NetStream.Publish.BadName":
					break;
			}
		}
	}
}
